<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    function defineReactive(target, key, value, enumerable) {
      //  函数内部是一个局部作用域，这个value就只在函数内部使用的作用
  
      /*
      判断是不是对象类型，是的话就继续递归
      */
      if(typeof value === 'object' && value != null && !Array.isArray(value)) {
        // 是非数组的引用类型
        reactify(value) ; // 递归
      }
  
      Object.defineProperty(target, key, {
        configurable: true,
        enumerable: !!enumerable,
        get() {
          console.log('读取o的'+key+'属性');
          return value
        },
        set(newVal) {
          console.log('设置o的'+key+'属性为：'+newVal);
          value = newVal
        }
      })
     }
      /*
      多级嵌套的响应式，数组，对象，多层，递归，
      */
     let data = {
       name: 'zs',
       age: 30,
       course: [
         {name: '语文'},
         {name: '数学'},
         {name: '英语'}
       ],
       user: {
         userInfo: {
           name: 'ls',
           age: 99
         }
       }
     }
     // 将对象o进行响应式化
     function reactify(o) {
      let keys = Object.keys(o)
      for(let i=0;i<keys.length;i++) {
        let key = keys[i]; // key属性名
        let value = o[key]
        /*
        判断这个属性是不是引用类型，判断是不是数据
        如果是引用类型就需要递归，否则就不用递归
        如果是数组？循环数组，将数组里边的元素进行响应式化
        不是引用类型，使用defineReactive2将其变成响应式
        是引用类型，也需要调用defineReactive2将其变成响应式
        */
       if(Array.isArray(value)) { // 数组
        for(let j=0;j<value.length;j++) {
          reactify(value[j]); // 递归
        }
       } else { // 对象或者值类型
         defineReactive(o, key, value, true)
      }
    }
     }
     reactify(data)
    </script>
</body>
</html>